WebGL 视图矩阵与透视投影配置
一句话结论:视图矩阵决定从哪看,投影矩阵决定看到多大范围和多深,两者与模型矩阵相乘构成完整的 MVP 变换。
视图矩阵与相机位置
是什么
视图矩阵把世界坐标系中的顶点转换到以相机为原点的相机坐标系。它由相机的位置、注视目标与上方向共同决定,是相机在世界变换的逆变换。
解决什么问题
它解决视角控制问题。场景中所有物体的顶点都存放在世界坐标里,要呈现"从某个位置看过去"的画面,就必须把整个场景按相机的相对位姿反向变换,让相机在变换后位于原点并朝向固定方向。
为什么这样做
移动相机与移动整个世界在数学上是等价的,但后者不需要修改任何物体数据。GPU 只需在顶点着色器里多乘一个矩阵,就能实现自由视角、第一人称漫游与轨道观察,成本极低。
怎么用
// lookAt:相机位置、注视点、上方向
const view = mat4.create();
mat4.lookAt(view,
[eyeX, eyeY, eyeZ], // 相机位置
[0, 0, 0], // 注视目标
[0, 1, 0] // 上方向
);
// 轨道相机:用球坐标算相机位置再 lookAt
const r = 5, theta = 0.8, phi = 1.2;
const eye = [
r * Math.sin(phi) * Math.cos(theta),
r * Math.cos(phi),
r * Math.sin(phi) * Math.sin(theta),
];
mat4.lookAt(view, eye, [0, 0, 0], [0, 1, 0]);
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
void main() {
gl_Position = uProjection * uView * uModel * vec4(aPosition, 1.0);
}
常见坑
- 把视图矩阵当成"相机位置"直接写入 → 原因:两者不是同一概念 → 处理:用 lookAt 由位置与目标生成矩阵
- 相机看向正上方导致画面翻转 → 原因:上方向与视线平行 → 处理:限制俯仰角,避免接近正负 90 度
- 每帧改变上方向造成画面抖动 → 原因:上方向参与正交化计算 → 处理:轨道相机固定使用世界 Y 轴
- 修改相机后忘记重算矩阵 → 原因:矩阵是快照 → 处理:相机参数变化后重新调用 lookAt
透视投影矩阵配置
是什么
透视投影矩阵把相机坐标系下的顶点映射到裁剪空间,并写入深度信息。配置参数是垂直视场角 fovy、宽高比 aspect、近平面 near 与远平面 far,四者共同决定画面视野、纵深范围与深度精度。
解决什么问题
它解决"三维场景如何变成二维画面"的问题。视场角决定能看多宽,宽高比保证画面比例正确,两个裁剪面剔除过近与过远的物体,同时把 z 值压缩到 -1 到 1 的裁剪区间供深度测试使用。
为什么这样做
人眼观察世界是透视的,平行线在远处汇聚,因此三维画面必须模拟这种收缩。投影矩阵通过把 w 分量设为与视空间 z 相关的值,让 GPU 的透视除法自动产生近大远小的效果,无需在着色器中手写缩放逻辑。
怎么用
const fovy = 45 * Math.PI / 180; // 垂直视场角,常用 45~60 度
const aspect = canvas.width / canvas.height;
const near = 0.1; // 尽量取大一些,提升深度精度
const far = 100;
const projection = mat4.create();
mat4.perspective(projection, fovy, aspect, near, far);
gl.uniformMatrix4fv(uProjection, false, projection);
| 参数 | 取值建议 | 影响 |
|---|---|---|
| fovy | 45°–60° | 过大画面畸变,过小像长焦 |
| aspect | 缓冲宽 / 缓冲高 | 不匹配画面被拉伸 |
| near | 尽量大(如 0.1–1) | 越小近处越精确但远处精度下降 |
| far | 覆盖场景即可 | 过大会浪费深度精度 |
常见坑
- 用 CSS 尺寸计算 aspect → 原因:应使用渲染缓冲尺寸 → 处理:用 canvas.width/height 计算
- near 设为 0 或极小值 → 原因:透视除法会发散且深度精度崩溃 → 处理:near 必须大于 0 并尽量取大
- near 与 far 跨度过大 → 原因:深度值非线性分布 → 处理:压缩 far,或对远景使用对数深度
- 窗口变化后画面变形 → 原因:投影矩阵未重算 → 处理:尺寸变化时同步重建投影矩阵与视口
要点总结
- 视图矩阵是相机变换的逆,用 lookAt 由位置、目标与上方向生成
- 投影矩阵四参数:视场角、宽高比、近平面、远平面
- aspect 必须用渲染缓冲尺寸计算,尺寸变化要重算矩阵与视口
- near 不能为 0,且应与 far 保持合理比例以保证深度精度
- MVP 顺序固定为投影 × 视图 × 模型,顺序写反画面会错乱
